<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1, minimum-scale=1, maximum-scale=1">
<meta name="renderer" content="webkit">
<meta name="google" value="notranslate">
<meta name="robots" content="index,follow">


<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Akkuman">
<meta name="twitter:description" content="Akkuman的技术博客">
<meta name="twitter:image:src" content="http://127.0.0.1:8000/images/avatar.png">

<meta property="og:url" content="http://127.0.0.1:8000">
<meta property="og:title" content="Akkuman">
<meta property="og:description" content="Akkuman的技术博客">
<meta property="og:site_name" content="Akkuman">
<meta property="og:image" content="http://127.0.0.1:8000/images/avatar.png">
<meta property="og:type" content="website">
<meta name="robots" content="noodp">

<meta itemprop="name" content="Akkuman">
<meta itemprop="description" content="Akkuman的技术博客">
<meta itemprop="image" content="http://127.0.0.1:8000/images/avatar.png">

<link rel="canonical" href="http://127.0.0.1:8000">

<link rel="shortcut icon" href="/favicon.png">
<link rel="apple-itouch-icon" href="/favicon.png">

<link type="text/css" rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/prism.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/zoom.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/main.css">
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>



<script>var cPlayers = [];var cPlayerOptions = [];</script>


<script type="text/javascript">
    var timeSinceLang = {
        year: '年前',
        month: '个月前',
        day: '天前',
        hour: '小时前',
        minute: '分钟前',
        second: '秒前'
    };
    var root = '';
</script>


        <meta name="keywords" content="Windows,ASM,读书笔记,汇编(ASM),">
        <meta name="description" content="Win32汇编学习(1)：基本概念">
        <meta name="author" content="Akkuman">
        <title>Win32汇编学习(1)：基本概念</title>
    </head>
    <body>
        
        <header id="header" class="clearfix">
  <div class="container-fluid">
      <div class="row">
          <div class="logo">
              <div class="header-logo">
                <script>
                  var getwbclass = function() {
                    var wbclass = ['b', 'w'];
                    return wbclass[Math.floor(Math.random()*wbclass.length)];
                  }
                  var sitetitle = "Akkuman";
                  for (i in sitetitle) {
                    document.write('<a href="/"><span class="' + getwbclass() + ' titlechar">' + sitetitle.charAt(i) + '</span></a>');
                  }          
                  
                </script>
                
                <a id="btn-menu" href="javascript:isMenu();">
                    <span class="b">·</span>
                </a>
                <a href="javascript:isMenu1();">
                    <span id="menu-1" class="bf">1</span>
                </a>
                <a href="javascript:isMenu2();">
                    <span id="menu-2" class="bf">2</span>
                </a>
                <a href="javascript:isMenu3();">
                    <span id="menu-3" class="bf">3</span>
                </a>
              </div>
              <div id="menu-page">
                <a href="/archive.html"><li>归档</li></a>
                <a href="/tag.html"><li>标签</li></a>
                
                <a href="/atom.xml"><li>订阅</li></a>
                
                <a href="about.html"><li>关于</li></a>
              </div>
              <div id="search-box">
                  <div id="search">
                      <input autocomplete="off" type="text" name="s" id="menu-search" placeholder="搜索..." data-root="" />
                  </div>
              </div>
          </div>
      </div>
  </div>
  </header>
        <div id="body" class="clearfix">
            <div class="container-fluid">
                <div class="row">
                    <div id="main" class="col-12 clearfix" role="main">
                        <article class="posti" itemscope itemtype="http://schema.org/BlogPosting">
                            <h1 class="post-title" itemprop="name headline">Win32汇编学习(1)：基本概念</h1>
                            <div class="post-meta">
                                <p>
                                    Written by <a itemprop="name" href="/about.me.html" rel="author">Akkuman</a> with ♥ on <time datetime="1517809540" itemprop="datePublished"></time> in <a href="/tag/Windows/index.html">Windows </a><a href="/tag/ASM/index.html">ASM </a><a href="/tag/%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0/index.html">读书笔记 </a><a href="/tag/%e6%b1%87%e7%bc%96%28ASM%29/index.html">汇编(ASM) </a>
                                </p>
                            </div>
                            <div class="post-content" itemprop="articleBody">
                                <h2>背景知识</h2>

<p>Windows 把每一个 Win32 应用程序放到分开的虚拟地址空间中去运行，也就是说每一个应用程序都拥有其相互独立的 4GB 地址空间，当然这倒不是说它们都拥有 4GB 的物理地址空间，而只是说能够在 4GB 的范围内寻址。操作系统将会在应用程序运行时完成 4GB 的虚拟地址和物理内存地址间的转换。这就要求编写应用程序时必须格守 Windows 的规范，否则极易引起内存的保护模式错误。而过去的 Win16 内存模式下，所有的应用程序都运行于同一个 4GB 地址空间，它们可以彼此&rdquo;看&rdquo;到别的程序的内容，这极易导致一个应用程序破坏另一个应用程序甚至是操作系统的数据或代码。</p>

<p>和 16 位 Windows 下的把代码分成 DATA，CODE 等段的内存模式不同，WIN32 只有一种内存模式，即 FLAT 模式，意思是&rdquo;平坦&rdquo;的内存模式，再没有 64K 的段大小限制，所有的 WIN32 的应用程序运行在一个连续、平坦、巨大的 4GB 的空间中。这同时也意味着您无须和段寄存器打交道，您可以用任意的段寄存器寻址任意的地址空间，这对于程序员来说是非常方便的，这也使得用32位汇编语言和用C语言一样方便。 在Win32下编程，有许多重要的规则需要遵守。有一条很重要的是：Windows 在内部频繁使用 ESI，EDI，EBP，EBX 寄存器，而且并不去检测这些寄存器的值是否被更改，这样当您要使用这些寄存器时必须先保存它们的值，待用完后再恢复它们，一个最显著的应用例子就是 Windows 的 CallBack 函数中。</p>

<h2>内容</h2>

<p>一般的Win32汇编都有下面的程序段，这是一个Win32汇编编程的基础框架，若您现在还不知道这些指令的确切意义的话，没关系， 随后我就会给大家详细解释。</p>

<pre><code class="language-asm">.386 
.MODEL Flat, STDCALL 
.DATA 
    &lt;Your initialized data&gt; 
    ...... 
.DATA? 
   &lt;Your uninitialized data&gt; 
   ...... 
.CONST 
   &lt;Your constants&gt; 
   ...... 
.CODE 
   &lt;label&gt; 
    &lt;Your code&gt; 
   ..... 
    end &lt;label&gt; 
</code></pre>

<p>这就是一般Win32汇编编程的基础框架，其中各个关键词的解释说明如下：</p>

<pre><code>.386
</code></pre>

<p>这是一个汇编语言伪指令，他告诉编译器我们的程序是使用80386指令集编写的。您还可以使用 .486、.586， 但最安全的还是使用.386。对于每一种CPU有两套几乎功能相同伪指令： .386/.386P、 486/.486P、 586/.586P。 带P的指令标明您的程序中可以用特权级指令。特权级指令是保留给操作系统的，如虚拟设备驱动程序。在大多数时间，您的程序都无须运行在RING0层，故用不带后缀P的伪指令已足够了。</p>

<pre><code>.MODEL FLAT，STDCALL 
</code></pre>

<p><code>.MODEL</code> 是用来指定内存模式的伪指令，在Win32下，只有一种内存模型，那就是FLAT。 <code>STDCALL</code> 告诉编译器参数的传递约定。参数的传递约定是指参数传达时的顺序(从左到右或从右到左)和由谁恢复堆栈指针(调用者或被调用者)。在Win16下有两种约定：<code>C</code> 和 <code>PASCAL</code>。C 约定规定参数传递顺序是从右到左，即最右边的参数最先压栈，由调用者恢复堆栈指针。</p>

<p>例如：为调用函数 <code>foo ( int first_param， int second_param， int third_param )</code>； 按C约定的汇编代码应该是这样的：</p>

<pre><code>push [third_param]
push [second_param]
push [first_param]
call foo
add esp， 3 * 4 ;调用者自己恢复堆栈指针
</code></pre>

<p><code>PASCAL</code>约定和<code>C</code>约定正好相反，它规定参数是从左向右传递，由被调用者恢复堆栈。Win16采用了<code>PASCAL</code>约定， 因为<code>PASCAL</code>约定产生的代码量要小。当不知道参数的个数时，<code>C</code>约定特别有用。如在函数<code>wsprintf ()</code> 中， <code>wsprintf</code>预先并不知道要传递几个参数，所以它不知道如何恢复堆栈。<code>STDCALL</code>是<code>C</code>约定和<code>PASCAL</code>约定的混合体，它规定参数的传递是从右到左，恢复堆栈的工作交由被调用者。Win32只用<code>STDCALL</code>约定，但除了一个特例，即：<code>wsprintf</code>。</p>

<pre><code>.DATA 
.DATA? 
.CONST 
.CODE
</code></pre>

<p>上面的四个伪指令是&rdquo;分段&rdquo;(SECTION)伪指令。我们上面刚讲过Win32下没有&rdquo;段&rdquo;(SEGMENT)的概念，但是您可以把您的程序分成不同的&rdquo;分段&rdquo;， 一个&rdquo;分段&rdquo;的开始即是上一个&rdquo;分段&rdquo;的结束。WIN32中只有两种性质的&rdquo;分段&rdquo;：<code>DATA</code>和<code>CODE</code>。</p>

<p>其中DATA&rdquo;分段&rdquo;又分为三种：
- <code>.DATA</code> 其中包括已初始化的数据。
- <code>.DATA?</code> 其中包括未初始化的数据。比如有时您仅想预先分配一些内存但并不想指定初始值。使用未初始化的数据的优点是它不占据可执行文件的大小，如：若您要在 <code>.DATA?</code> 段中分配10,000字节的空间，您的可执行文件的大小无须增加10,000字节，而仅仅是要告诉编译器在装载可执行文件时分配所需字节。
- <code>.CONST</code> 其中包括常量定义。这些常量在程序运行过程中是不能更改的。 应用程序并不需要以上所有的三个&rdquo;分段&rdquo;， 可以根据需要进行定义。
- <code>.CODE</code> 这是代码&rdquo;分段&rdquo;。
&gt; 实际上，分段并不是象在 Dos 下一样，为不同的段分别指出不同的段寄存器，因为 Windows 下只有一个 4GB 的段，Windows 程序中的分段表现在当程序装载时，赋予不同的分段不同的属性，比如说当你的程序加载时，对于 Ring3 程序来说，.code 段是不可写的，而 .data 段是可写的，如果你尝试象在 Dos 下一样写自己的代码部分，你会得到一个蓝屏错误</p>

<pre><code>&lt;label&gt; 
end &lt;label&gt; 
</code></pre>

<p>是用来唯一标识您的代码范围的标签， 两个标签必须相同，应用程序的所有可执行代码必须在两个标签之间。</p>

                            </div>
                            <div style="display:block;" class="clearfix">
                                <section style="float:left;">
                                    <span itemprop="keywords" class="tags">
                                        tag(s): <a href="/tag/Windows/index.html">Windows </a><a href="/tag/ASM/index.html">ASM </a><a href="/tag/%e8%af%bb%e4%b9%a6%e7%ac%94%e8%ae%b0/index.html">读书笔记 </a><a href="/tag/%e6%b1%87%e7%bc%96%28ASM%29/index.html">汇编(ASM) </a>
                                    </span>
                                </section>
                                <section style="float:right;">
                                    <span><a id="btn-comments" href="javascript:isComments();">show comments</a></span> · <span><a href="javascript:goBack();">back</a></span> · 
                                    <span><a href="/">home</a></span>
                                </section>
                            </div>
                            



<div id="comments" class="gen">
    <script>
        document.write('<section id="disqus_thread"></section>');
        var site_comment_load = function disqus() {
            var d = document, s = d.createElement('script');
            s.src = '//Akkum4n.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        }
    </script>
</div>

                        </article>
                    </div>
                </div>
            </div>
        </div>
        <footer id="footer" role="contentinfo">
    <div class="container-fluid">
        <div class="row">
        <div class="col-12">
            &copy; 
            <script type="text/javascript">
                document.write(new Date().getFullYear());
            </script>
            <a href="/">Akkuman</a>.
            Using <a target="_blank" href="http://www.chole.io/">Ink</a> & <a target="_blank" href="/">Story</a>.
        </div>
        </div>
    </div>
</footer>

<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="/bundle/js/prism.js"></script>
<script src="/bundle/js/zoom-vanilla.min.js"></script>
<script src="/bundle/js/main.js"></script>

<script>
    window.onload=function(){
        if (window.location.hash!='') {
          var i=window.location.hash.indexOf('#comment');
          var ii=window.location.hash.indexOf('#respond-post');
          if (i != '-1' || ii != '-1') {
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
          }
        }
    }

    function isMenu(){
        if(document.getElementById('menu-1').style.display=='inline'||document.getElementById('menu-1').style.display=='block'){
            $('#search-box').fadeOut(200);
            $('#menu-page').fadeOut(200);
            $('#menu-1').fadeOut(500);
            $('#menu-2').fadeOut(400);
            $('#menu-3').fadeOut(300);
        } else {
            $('#menu-1').fadeIn(150);
            $('#menu-2').fadeIn(150);
            $('#menu-3').fadeIn(150);
        }
    }

    function isMenu1(){
        if(document.getElementById('menu-page').style.display=='block'){
            $('#menu-page').fadeOut(300);
        } else {
            $('#menu-page').fadeIn(300);
        }
    }

    function isMenu2(){
        if(document.getElementById('torTree')){
            if(document.getElementById('torTree').style.display=='block'){
                $('#torTree').fadeOut(300);
            } else {
                $('#torTree').fadeIn(300);
            }
        }
    }

    function isMenu3(){
        if(document.getElementById('search-box').style.display=='block'){
            $('#search-box').fadeOut(300);
        } else {
            $('#search-box').fadeIn(300);
        }
    }

    function isComments(){
        if(document.getElementById('btn-comments').innerText=='show comments'){
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
            site_comment_load();
        } else {
            document.getElementById('btn-comments').innerText='show comments';
            document.getElementById('comments').style.display='none';
        }
    }

    function Search404(){
        $('#menu-1').fadeIn(150);
        $('#menu-2').fadeIn(150);
        $('#menu-3').fadeIn(150);
        $('#search-box').fadeIn(300);
    }

    function goBack(){
        window.history.back();
    }
</script>


<script async>
"use strict";
(function(){
var cp = function(){
    var len = cPlayerOptions.length;
    for(var i=0;i<len;i++){
        var element = document.getElementById('player' + cPlayerOptions[i]['id'])
        while (element.hasChildNodes()) {
            element.removeChild(element.firstChild);
        };
        cPlayers[i] = new cPlayer({
            element: element,
            list: cPlayerOptions[i]['list'],
            });
    };
    cPlayers = [];cPlayerOptions = [];
};
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "https://cdn.bootcss.com/cplayer/3.2.1/cplayer.js";
script.async = true;
if(script.readyState){  
    script.onreadystatechange = function(){
        if (script.readyState == "loaded" ||
            script.readyState == "complete"){
            script.onreadystatechange = null;
            cp();
        }
    };
}else{  
    script.onload = function(){
        cp();
    };
}
document.head.appendChild(script);
})();
</script>

    </body>
</html>
